package org.blogwu.learn.threadLearn.自己实现一个重入锁;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.LockSupport;

/**
 * 自己实现的重入锁
 * 加锁：如果共享变量有数据就挂起当前线程，如果为null就吧当前变量赋值到 共享变量(监视器)
 * 解锁：首先吧自己的共享变量设置为null，然后在重等待队列中唤醒一个线程；
 *
 * @author hyf
 * @date 2019-05-24
 **/
public class DemoLock {

    volatile AtomicReference<Object> reference = new AtomicReference<>();

//    Object object = null;

    volatile LinkedBlockingQueue<Thread> waits = new LinkedBlockingQueue<Thread>();

    public void lock() {
        // 1 非原子性
//        if ( this.object == null ){
//            object = Thread.currentThread();
//        }else{
//            waits.add( Thread.currentThread() );
//            LockSupport.park();
//        }
        // 2 如果当前值=预期值，则自动将该值设置为给定的更新值。
//        if ( !reference.compareAndSet( null, Thread.currentThread() )){
//            // 下面这段代码有问题，如果 线程1为获取锁，加入等待队列，但是这是后线程2 刚好从 等待队列中取一个线程unpack(),但是线程1马上执行
//            // park()。所以线程1 就永远阻塞在哪了
//            //  也就是这儿不是原子操作
//             waits.add( Thread.currentThread() );
//            LockSupport.park();
//        }


        // 3. 这样的话，即使放进去，马上另一边有取出现。这时候还是会去参与竞争，不会有问题
        // 如果放在if里面，刚刚放进去，马上另一个线程取出来就会复现2 的bug。
        waits.add(Thread.currentThread());
        if (!reference.compareAndSet(null, Thread.currentThread())) {
//            System.out.println(Thread.currentThread().getName() + "睡眠");
            // 调用了park就阻塞了
            LockSupport.park();
        }
        // 这而做的目的就是 如果成功就清除掉当前的 ，如果失败呢，会被park阻塞，呗唤醒后不管出现什么意外情况，则都会保证当前线程不会存在在等待队列
        waits.remove(Thread.currentThread());

    }

    public void unlock() {
        if (reference.compareAndSet(Thread.currentThread(), null)) {
//            System.out.println(Thread.currentThread().getName() + "唤醒");
//            LockSupport.unpark( waits.poll() ); // 这儿还有什么问题？
            // 释放锁之后，要唤醒线程(所有 -- 惊群效应)
            for (Thread waiter : waits) {
                LockSupport.unpark(waiter);
            }
        }
    }

}
